<!DOCTYPE html>
<html lang="zh-cn">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title>IPC之二：使用命名管道(FIFO)进行进程间通信的例子 - whowin - 发表我个人原创作品的技术博客</title>
  <meta name="renderer" content="webkit" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>

<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />

<meta name="theme-color" content="#f8f5ec" />
<meta name="msapplication-navbutton-color" content="#f8f5ec">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="#f8f5ec">


<meta name="author" content="whowin" /><meta name="description" content="IPC 是 Linux 编程中一个重要的概念，IPC 有多种方式，本文主要介绍命名管道(FIFO)，命名管道可以完成同一台计算机上的进程之间的通信，本文给出了多个具体的实例，每个实例均附有完整的源代码；本文所有实例在 Ubuntu 20.04 上编译测试通过，gcc版本号为：9.4.0；本文适合 Linux 编程的初学者阅读。
" /><meta name="keywords" content="linux, socket, hugo, dos" />






<meta name="generator" content="Hugo 0.97.3 with theme even" />


<link rel="canonical" href="https://whowin.gitee.io/post/blog/ipc/0011-ipc-examples-of-fifo/" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/manifest.json">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">



<link href="/sass/main.min.e3fea119b1980e848b03dffbeddb11dd0fba483eed0e5f11870fb8e31f145bbd.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.1.20/dist/jquery.fancybox.min.css" integrity="sha256-7TyXnr2YU040zfSP+rEcz29ggW4j56/ujTPwjMzyqFY=" crossorigin="anonymous">


<meta property="og:title" content="IPC之二：使用命名管道(FIFO)进行进程间通信的例子" />
<meta property="og:description" content="IPC 是 Linux 编程中一个重要的概念，IPC 有多种方式，本文主要介绍命名管道(FIFO)，命名管道可以完成同一台计算机上的进程之间的通信，本文给出了多个具体的实例，每个实例均附有完整的源代码；本文所有实例在 Ubuntu 20.04 上编译测试通过，gcc版本号为：9.4.0；本文适合 Linux 编程的初学者阅读。" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://whowin.gitee.io/post/blog/ipc/0011-ipc-examples-of-fifo/" /><meta property="article:section" content="post" />
<meta property="article:published_time" content="2023-08-02T16:43:29+08:00" />
<meta property="article:modified_time" content="2023-08-02T16:43:29+08:00" />

<meta itemprop="name" content="IPC之二：使用命名管道(FIFO)进行进程间通信的例子">
<meta itemprop="description" content="IPC 是 Linux 编程中一个重要的概念，IPC 有多种方式，本文主要介绍命名管道(FIFO)，命名管道可以完成同一台计算机上的进程之间的通信，本文给出了多个具体的实例，每个实例均附有完整的源代码；本文所有实例在 Ubuntu 20.04 上编译测试通过，gcc版本号为：9.4.0；本文适合 Linux 编程的初学者阅读。"><meta itemprop="datePublished" content="2023-08-02T16:43:29+08:00" />
<meta itemprop="dateModified" content="2023-08-02T16:43:29+08:00" />
<meta itemprop="wordCount" content="6899">
<meta itemprop="keywords" content="Linux,进程间通信,IPC,FIFO,命名管道," /><meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="IPC之二：使用命名管道(FIFO)进行进程间通信的例子"/>
<meta name="twitter:description" content="IPC 是 Linux 编程中一个重要的概念，IPC 有多种方式，本文主要介绍命名管道(FIFO)，命名管道可以完成同一台计算机上的进程之间的通信，本文给出了多个具体的实例，每个实例均附有完整的源代码；本文所有实例在 Ubuntu 20.04 上编译测试通过，gcc版本号为：9.4.0；本文适合 Linux 编程的初学者阅读。"/>

<!--[if lte IE 9]>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.1.20170427/classList.min.js"></script>
<![endif]-->

<!--[if lt IE 9]>
  <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
<![endif]-->

  <script async src="/js/busuanzi.pure.mini.js"></script><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9724909319263152"
     crossorigin="anonymous"></script>


</head>
<body>
  <div id="mobile-navbar" class="mobile-navbar">
  <div class="mobile-header-logo">
    <a href="/" class="logo">WhoWin</a>
  </div>
  <div class="mobile-navbar-icon">
    <span></span>
    <span></span>
    <span></span>
  </div>
</div>
<nav id="mobile-menu" class="mobile-menu slideout-menu">
  <ul class="mobile-menu-list">
    <a href="/">
        <li class="mobile-menu-item">首页</li>
      </a><a href="/post/">
        <li class="mobile-menu-item">文章归档</li>
      </a><a href="/article-categories/categories/">
        <li class="mobile-menu-item">文章分类</li>
      </a><a href="/tags/">
        <li class="mobile-menu-item">文章标签</li>
      </a><a href="/about/about/">
        <li class="mobile-menu-item">关于</li>
      </a>
  </ul>

  


</nav>

  <div class="container" id="mobile-panel">
    <header id="header" class="header">
        <div class="logo-wrapper">
  <a href="/" class="logo">WhoWin</a>
  
  <div style="position:absolute; left: 80px; top: 75px; color: crimson">
      ———开源和分享是技术发展的源泉和动力；本博客所有文章均为原创
  </div>
</div>





<nav class="site-navbar">
  <ul id="menu" class="menu">
    <li class="menu-item">
        <a class="menu-item-link" href="/">首页</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/post/">文章归档</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/article-categories/categories/">文章分类</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/tags/">文章标签</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/about/about/">关于</a>
      </li>
  </ul>
</nav>

    </header>

    <main id="main" class="main">
      <div class="content-wrapper">
        <div id="content" class="content">
          <article class="post">
    
    <header class="post-header">
      <h1 class="post-title">IPC之二：使用命名管道(FIFO)进行进程间通信的例子</h1>

      <div class="post-meta">
        <span class="post-time"> 2023-08-02 </span>
        <div class="post-category">
            <a href="/categories/ipc/"> IPC </a>
            <a href="/categories/linux/"> Linux </a>
            <a href="/categories/c-language/"> C Language </a>
            </div>
        
      </div>
    </header>

    <div class="post-toc" id="post-toc">
  <h2 class="post-toc-title">文章目录</h2>
  <div class="post-toc-content always-active">
    <nav id="TableOfContents">
  <ul>
    <li>
      <ul>
        <li><a href="#1-命名管道fifo的基本概念">1 命名管道(FIFO)的基本概念</a></li>
        <li><a href="#2-在-shell-下建立一个命名管道fifo">2 在 shell 下建立一个命名管道(FIFO)</a></li>
        <li><a href="#3-使用c语言创建命名管道">3 使用C语言创建命名管道</a></li>
        <li><a href="#4-命名管道fifo的实例">4 命名管道(FIFO)的实例</a></li>
        <li><a href="#5-命名管道fifo的阻塞机制">5 命名管道(FIFO)的阻塞机制</a></li>
        <li><a href="#6-sigpipe-信号和-eof">6 SIGPIPE 信号和 EOF</a></li>
        <li><a href="#7-使用流式文件操作-fifo-的一些差异">7 使用流式文件操作 FIFO 的一些差异</a></li>
        <li><a href="#8-后记">8 后记</a></li>
        <li><a href="#欢迎订阅-进程间通信专栏httpsblogcsdnnetwhowincategory_12404164html"><strong>欢迎订阅 <a href="https://blog.csdn.net/whowin/category_12404164.html">『进程间通信专栏』</a></strong></a></li>
      </ul>
    </li>
  </ul>
</nav>
  </div>
</div>
    <div class="post-content">
      <p>IPC 是 Linux 编程中一个重要的概念，IPC 有多种方式，本文主要介绍命名管道(FIFO)，命名管道可以完成同一台计算机上的进程之间的通信，本文给出了多个具体的实例，每个实例均附有完整的源代码；本文所有实例在 Ubuntu 20.04 上编译测试通过，gcc版本号为：9.4.0；本文适合 Linux 编程的初学者阅读。</p>
<h2 id="1-命名管道fifo的基本概念">1 命名管道(FIFO)的基本概念</h2>
<ul>
<li>
<p>FIFO(First-In First-Out)，在 Linux 文件系统中是一种特殊的文件，相对于匿名管道，FIFO 又被称为命名管道；</p>
</li>
<li>
<p>在我的另一篇文章<a href="https://whowin.gitee.io/post/blog/ipc/0010-ipc-example-of-anonymous-pipe/">《IPC之一：使用匿名管道进行父子进程间通信的例子》</a>中，介绍了管道(又称匿名管道)的基本概念；</p>
</li>
<li>
<p>匿名管道和命名管道本质上是一种东西，在内核中都是一个 <code>inode</code>，只是因为匿名管道在物理文件系统中没有文件故而仅能通过进程间的继承来传递这个 <code>inode</code> 的索引号；而命名管道因为有了物理文件系统中的文件，通过这个文件可以找到内核中相应的 <code>inode</code>，故而对该文件有读写权限的进程均可以使用这个管道；</p>
</li>
<li>
<p>命名管道的工作方式与匿名管道非常相似，但有一些明显的差异：</p>
<ol>
<li>命名管道作为一种特殊文件存在于文件系统中，匿名管道仅存在于内核中，不存在于文件系统中；</li>
<li>不同祖先的进程可以通过命名管道交换数据，而匿名管道只能在有共同祖先的进程间进行通信；</li>
<li>命名管道的生命周期可以大于使用它的进程的生命周期，也就是说，当使用命名管道交换数据的所有进程都终止后，命名管道仍然可以保留在文件系统中供以后使用；匿名管道则不同，当使用匿名管道的进程全部终止后，匿名管道也会消亡。</li>
</ol>
</li>
<li>
<p>当进程通过命名管道交换数据时，内核会在内部传递所有数据，而不将其写入文件系统；因此，表示一个命名管道的特殊文件在文件系统上没有内容；文件系统中表示命名管道的文件名仅充当参考点，以便进程可以使用文件系统中的文件名找到内核中的 <code>inode</code>，从而访问管道。</p>
</li>
<li>
<p>每个 FIFO 特殊文件代表着一个命名管道，由内核进行维护，必须先打开 FIFO 两端(读和写)，然后才能传递数据；一般情况下，打开 FIFO 会产生阻塞，直到另一端也打开为止，后面我们会专门讨论 FIFO 的阻塞问题；</p>
</li>
<li>
<p>进程也可以以非阻塞模式打开 FIFO；</p>
<ul>
<li>在使用非阻塞方式打开 FIFO 时，即便没有进程打开 FIFO 的写入端，一个进程以只读方式打开 FIFO 也会成功；</li>
<li>即便是以非阻塞方式打开 FIFO，如果没有进程打开 FIFO 的读出端，以只写方式打开 FIFO 也会失败，产生错误：No such device or address</li>
</ul>
</li>
<li>
<p>以读写方式打开 FIFO 不管是在阻塞还是非阻塞方式下都会成功，其返回的文件描述符既是写入端又是读出端，以这种方式打开的 FIFO，既可以做写入端使用，也可以做读出端使用，但通常只能使用其一端(要么写入要么读出)。</p>
</li>
</ul>
<h2 id="2-在-shell-下建立一个命名管道fifo">2 在 shell 下建立一个命名管道(FIFO)</h2>
<ul>
<li>
<p>有多种方法可以创建命名管道，其中下面两种方法可以直接在 shell 中创建命名管道；</p>
</li>
<li>
<p><strong>使用 <code>mknod</code> 命令建立命名管道</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mknod myfifo p
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>
<p><code>mknod</code> 命令用于创建一个特殊文件，命令最后的参数 &ldquo;p&rdquo;，表示建立一个 FIFO 特殊文件，这个参数还可以是 <code>b、c、u</code>，分别表示其它的特殊文件；</p>
</li>
<li>
<p>可以使用在线手册 <code>man mknod</code> 了解 <code>mknod</code> 命令的详细信息；</p>
</li>
<li>
<p>使用 <code>ls -l myfifo</code> 可以查看我们刚刚创建的 FIFO，文件权限最前面的 &ldquo;p&rdquo;，表示这个文件是个命名管道 FIFO；</p>
<p><img src="https://whowin.gitee.io/images/190011/screenshot-ls-fifo.png" alt="Screenshot for ls fifo"></p>
</li>
<li>
<p>使用 <code>mknod</code> 创建 FIFO 时，可以使用参数 <code>-m 权限</code> 来设置权限，比如：<code>mknod -m 0644 myfifo p</code> 命令，创建的 FIFO 只有拥有者可读写，其它用户只读；</p>
</li>
</ul>
</li>
<li>
<p><strong>使用 <code>mkfifo</code> 命令建立命名管道</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkfifo myfifo
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li><code>mkfifo</code> 命令用于创建一个 FIFO 特殊文件；</li>
<li>可以使用在线手册 <code>man mkfifo</code> 了解 <code>mkfifo</code> 命令的详细信息；</li>
<li>使用 <code>mkfifo</code> 创建 FIFO 时，可以像 <code>mknod</code> 命令一样使用参数 <code>-m 权限</code> 来设置权限，比如：<code>mkfifo -m 0666 myfifo</code> 命令，创建一个 FIFO，所有用户可读写；</li>
</ul>
</li>
<li>
<p>用 <code>mknod</code> 和 <code>mkfifo</code> 创建的 FIFO 可以用 <code>chmod</code> 修改权限</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkfifo -m <span class="m">0644</span> myfifo
</span></span><span class="line"><span class="cl">chmod <span class="nv">a</span><span class="o">=</span>rw myfifo
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li><code>mkfifo</code> 创建了一个 FIFO，<code>chmod</code> 将其权限改为所有用户可读写。</li>
</ul>
</li>
<li>
<p>用 <code>mknod</code> 和 <code>mkfifo</code> 创建的 FIFO 可以用 <code>rm</code> 删除</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">rm myfifo
</span></span></code></pre></td></tr></table>
</div>
</div></li>
</ul>
<h2 id="3-使用c语言创建命名管道">3 使用C语言创建命名管道</h2>
<ul>
<li>
<p>使用系统调用 mknod() 创建命名管道</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="err">原型：#</span><span class="n">include</span> <span class="o">&lt;</span><span class="n">sys</span><span class="o">/</span><span class="n">types</span><span class="p">.</span><span class="n">h</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">     <span class="cp">#include</span> <span class="cpf">&lt;sys/stat.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>     <span class="cp">#include</span> <span class="cpf">&lt;fcntl.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>     <span class="cp">#include</span> <span class="cpf">&lt;unistd.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl">     <span class="kt">int</span> <span class="n">mknod</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">pathname</span><span class="p">,</span> <span class="n">mode_t</span> <span class="n">mode</span><span class="p">,</span> <span class="n">dev_t</span> <span class="n">dev</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="err">说明：</span><span class="n">mknod</span><span class="p">()</span> <span class="err">可以在文件系统上建立一个文件节点</span><span class="p">(</span><span class="err">普通文件、特殊文件、命名管道</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="err">返回：调用成功返回</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">     <span class="err">调用失败返回</span> <span class="o">-</span><span class="mi">1</span>
</span></span><span class="line"><span class="cl">     <span class="n">errno</span> <span class="o">=</span> <span class="n">EFAULT</span> <span class="p">(</span><span class="n">pathname</span> <span class="n">invalid</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">             <span class="n">EACCES</span> <span class="p">(</span><span class="n">permission</span> <span class="n">denied</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">             <span class="n">ENAMETOOLONG</span> <span class="p">(</span><span class="n">pathname</span> <span class="n">too</span> <span class="kt">long</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">             <span class="n">ENOENT</span> <span class="p">(</span><span class="n">invalid</span> <span class="n">pathname</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">             <span class="n">ENOTDIR</span> <span class="p">(</span><span class="n">invalid</span> <span class="n">pathname</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">             <span class="p">(</span><span class="err">其它错误码请查看</span> <span class="n">man</span> <span class="err">手册</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>
<p>pathname 是文件路径不用多说</p>
</li>
<li>
<p>mode 是文件类型和文件权限，比如：<code>S_IFIFO | 0666</code> 表示建立一个 FIFO 特殊文件，权限为 <code>0666</code> (所有用户可读写)</p>
</li>
<li>
<p>dev 是设备号，只有当文件类型为 <code>S_IFCHR 或 S_IFBLK</code> 时，才有设备号，其他文件类型填 0 即可；</p>
</li>
<li>
<p>在线手册 <code>man 2 mknod</code> 可以查询该系统调用的详细信息</p>
</li>
<li>
<p>下面的调用创建了一个 FIFO 文件：<code>/tmp/myfifo</code>，权限为：<code>0666</code> (所有用户可读写)</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="n">mknod</span><span class="p">(</span><span class="s">&#34;/tmp/myfifo&#34;</span><span class="p">,</span> <span class="n">S_IFIFO</span> <span class="o">|</span> <span class="mo">0666</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>但实际上设置的文件权限还要受到 <code>umask</code> 的影响，最终的文件权限是 <code>0666 &amp; ~umask</code></p>
</li>
<li>
<p>可以使用 shell 命令 <code>umask</code> 查看当前的 <code>umask</code></p>
<p><img src="https://whowin.gitee.io/images/190011/screenshot-of-umask.png" alt="Screenshot of umask"></p>
</li>
<li>
<p>为了保证创建的 FIFO 文件的权限，可以在调用 <code>mknod()</code> 前临时删除 <code>umask</code></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="n">umask</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">mknod</span><span class="p">(</span><span class="s">&#34;/tmp/myfifo&#34;</span><span class="p">,</span> <span class="n">S_IFIFO</span><span class="o">|</span><span class="mo">0666</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div></li>
</ul>
</li>
<li>
<p>使用 mknodat() 创建命名管道</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="err">原型：#</span><span class="n">include</span> <span class="o">&lt;</span><span class="n">fcntl</span><span class="p">.</span><span class="n">h</span><span class="o">&gt;</span>           <span class="cm">/* Definition of AT_* constants */</span>
</span></span><span class="line"><span class="cl">     <span class="cp">#include</span> <span class="cpf">&lt;sys/stat.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl">     <span class="kt">int</span> <span class="n">mknodat</span><span class="p">(</span><span class="kt">int</span> <span class="n">dirfd</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">pathname</span><span class="p">,</span> <span class="n">mode_t</span> <span class="n">mode</span><span class="p">,</span> <span class="n">dev_t</span> <span class="n">dev</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>与 <code>mknod()</code> 相比，这个系统调用多了一个参数 <code>dirfd</code>，<code>dirfd</code> 是文件系统中一个打开的目录的文件描述符；</li>
<li>当 pathname 为绝对路径时，参数 <code>dirfd</code> 被忽略，该调用与 <code>mknod()</code> 完全一样；</li>
<li>当 pathname 为相对路径时，它是相对于 <code>dirfd</code> 所引用的目录，而不是相对于调用进程的当前工作目录；</li>
<li><code>mknod()</code> 中的 <code>pathname</code> 也是可以使用相对路径的，但是相对于调用进程时的当前目录；</li>
<li>下面代码使用 <code>mknodat()</code> 创建了一个 FIFO 文件：
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">dirfd</span> <span class="o">=</span> <span class="n">open</span><span class="p">(</span><span class="s">&#34;/tmp&#34;</span><span class="p">,</span> <span class="n">O_RDONLY</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">mknodat</span><span class="p">(</span><span class="n">dirfd</span><span class="p">,</span> <span class="s">&#34;./myfifo&#34;</span><span class="p">,</span> <span class="n">S_IFIFO</span><span class="o">|</span><span class="mo">0666</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> 
</span></span></code></pre></td></tr></table>
</div>
</div></li>
</ul>
</li>
<li>
<p>使用系统调用 mkfifo() 创建命名管道</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="err">原型：#</span><span class="n">include</span> <span class="o">&lt;</span><span class="n">sys</span><span class="o">/</span><span class="n">types</span><span class="p">.</span><span class="n">h</span><span class="o">&gt;</span>
</span></span><span class="line"><span class="cl">     <span class="cp">#include</span> <span class="cpf">&lt;sys/stat.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl">     <span class="kt">int</span> <span class="n">mkfifo</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">pathname</span><span class="p">,</span> <span class="n">mode_t</span> <span class="n">mode</span><span class="p">);</span>    
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li>毫无疑问，<code>mkfifo()</code> 就是专门用来创建 FIFO 文件的，<code>pathname</code> 为 FIFO 文件路径，<code>mode</code> 为文件权限，当然这个权限还要受到 <code>umask</code> 的影响，请参考前面的说明。</li>
</ul>
</li>
<li>
<p>使用系统调用 mkfifoat() 创建命名管道</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;fcntl.h&gt;           /* Definition of AT_* constants */</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;sys/stat.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">mkfifoat</span><span class="p">(</span><span class="kt">int</span> <span class="n">dirfd</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">pathname</span><span class="p">,</span> <span class="n">mode_t</span> <span class="n">mode</span><span class="p">);</span>    
</span></span></code></pre></td></tr></table>
</div>
</div><ul>
<li><code>mkfifoat()</code> 与 <code>mkfifo()</code> 的关系与 <code>mknodat()</code> 与 <code>mknod()</code> 的关系一样，请参考 <code>mknodat()</code> 的说明</li>
</ul>
</li>
</ul>
<h2 id="4-命名管道fifo的实例">4 命名管道(FIFO)的实例</h2>
<ul>
<li>
<p>在命名管道上的 I/O 操作与匿名管道是一样的，使用 <code>read()</code> 从管道中读出数据，使用 <code>write()</code> 向管道中写入数据，不能使用 <code>lseek()</code> 等；</p>
</li>
<li>
<p>有一个明显的区别是在对命名管道进行 I/O 操作之前，必须用 <code>open()</code> 打开 FIFO 文件，这在匿名管道上是不需要的，因为匿名管道仅存在于内核中，并不存在于物理的文件系统中，而命名管道是存在于物理文件系统中的；</p>
</li>
<li>
<p>由于 FIFO 文件存在于文件系统中，所以，对命名管道也可以使用流式文件的 I/O 操作，即：</p>
<ul>
<li><code>fopen()</code> 打开 FIFO 文件</li>
<li>使用 <code>fgetc()/fputc()、fgets()/fputs()</code> 进行读写操作；或者</li>
<li>使用 <code>fscanf()/fprintf()</code> 进行读写操作；或者</li>
<li>使用 <code>fread()/fwrite()</code> 进行读写操作；</li>
<li><code>fclose()</code> 关闭 FIFO 文件</li>
</ul>
</li>
<li>
<p>下面是一个使用 FIFO 传递消息的实例，分为两个独立的程序</p>
<ul>
<li>服务端源程序：<a href="https://gitee.com/whowin/whowin/blob/blog/sourcecodes/190011/fifo-server.c">fifo-server.c</a>(<strong>点击文件名下载源程序</strong>)，从 FIFO 上接收数据</li>
<li>客户端源程序：<a href="https://gitee.com/whowin/whowin/blob/blog/sourcecodes/190011/fifo-client.c">fifo-client.c</a>(<strong>点击文件名下载源程序</strong>)，向 FIFO 中写入消息</li>
<li>这个实例中使用 <code>fopen()</code> 打开 FIFO，客户端使用 <code>fputs()</code> 向 FIFO 中写入数据，服务端使用 <code>fgets()</code> 从 FIFO 中读出数据，使用 <code>fclose()</code> 关闭 FIFO；</li>
<li>也可以使用 <code>open()/write()/read()/close()</code> 这组系统调用来进行 FIFO 的操作；</li>
<li>这个实例使用 <code>mknod()</code> 创建 FIFO，当然也可以使用 <code>mkfifo()</code> 创建 FIFO；</li>
<li>其实这个实例中也可以不使用 <code>fifo-client</code> 这个程序，我们可以在 shell 下使用 <code>echo &quot;Hello World!&quot;&gt;myfifo</code> 来代替 <code>fifo-client</code> 完成向 FIFO 发送信息的功能；</li>
<li><code>fifo-client</code> 程序演示了使用流式文件向 FIFO 中写入数据的方法，特别要注意的是程序最后的 <code>fflush()</code>，在本例中，<code>fflush()</code> 并不是必须的，因为紧接着就使用了 <code>fclose()</code>，但在很多情况下，如果不使用 <code>fflush()</code>，数据会被缓存起来，不会立即发送出去。</li>
</ul>
</li>
<li>
<p>FIFO 这种特殊文件有些地方确实特殊：</p>
<ul>
<li>从 FIFO 中读数据的进程在打开 FIFO 时会阻塞，直到有一个向这个 FIFO 中写数据的进程打开 FIFO；</li>
<li>向 FIFO 中写数据的进程在打开 FIFO 时会阻塞，直到有一个从这个 FIFO 中读数据的进程打开 FIFO;</li>
<li>进程从 FIFO 中读数据时会阻塞，直到有进程向 FIFO 中写入数据；</li>
<li>向一个没有读出端的 FIFO 中写入数据时，会产生错误；
<blockquote>
<p>这种情况通常发生在 FIFO 两端正常打开后，读出端关闭，导致管道没有读出端</p>
</blockquote>
</li>
</ul>
</li>
<li>
<p>编译运行</p>
<ul>
<li>编译
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">gcc -Wall fifo-server.c -o fifo-server
</span></span><span class="line"><span class="cl">gcc -Wall fifo-client.c -o fifo-client
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>这个实例需要在两个终端中运行，一个终端中运行 <code>./fifo-server</code>；另一个终端中运行 <code>./fifo-client &quot;Hello world!&quot;</code></li>
<li>初次运行时，要先运行 <code>./fifo-server</code> 再运行 <code>./fifo-client</code>，因为 FIFO 文件是在 <code>fifo-server</code> 程序中创建的；</li>
<li><code>fifo-server</code> 不会自行退出，需要在键盘上输入 <code>ctrl+c</code> 才能退出；</li>
<li><code>fifo-client</code> 可以在 shell 下使用命令：<code>echo &quot;Hello world!&quot;&gt;myfifo</code> 来代替。</li>
</ul>
</li>
<li>
<p><code>fifo-server</code> 的运行截图：</p>
<p><img src="https://whowin.gitee.io/images/190011/screenshot-fifo-server.png" alt="Screen of fifo-server"></p>
</li>
</ul>
<hr>
<h2 id="5-命名管道fifo的阻塞机制">5 命名管道(FIFO)的阻塞机制</h2>
<ul>
<li>
<p>打开 FIFO 有三种方式：只读方式、只写方式和读写方式</p>
</li>
<li>
<p>使用阻塞方式(没有 O_NONBLOCK 标志)打开 FIFO</p>
<ul>
<li>以只读方式(O_RDONLY)打开 FIFO 的读出端会发生阻塞，直至 FIFO 写入端被其它进程打开；</li>
<li>以只写方式(O_WRONLY)打开 FIFO 的写入端会发生阻塞，直至 FIFO 读出端被其它进程打开；</li>
<li>以读写方式(O_RDWR)方式打开 FIFO 会直接返回成功，因为打开的 FIFO 描述符既可作读出端，也可以作写入端，相当于打开了 FIFO 的两端；</li>
<li>以只读方式(O_RDONLY)成功打开的 FIFO，在读出数据时：
<ul>
<li>如果写入端打开，则发生阻塞，直到写入端将数据写入 FIFO 后，返回读出的数据长度(字符数)；</li>
<li>如果写入端关闭，则立即返回 EOF(读出数据长度为 0)；</li>
</ul>
</li>
<li>以只写方式(O_WRONLY)成功打开的 FIFO，向 FIFO 写入数据时：
<ul>
<li>如果读出端打开，则会直接返回成功，读出端可以正常读出数据；</li>
<li>如果读出端关闭，则出现错误，并产生 SIGPIPE 信号。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>使用非阻塞方式(设置 O_NONBLOCK 标志)打开 FIFO</p>
<ul>
<li>以只读方式(O_RDONLY)打开 FIFO 时不会阻塞，返回成功；</li>
<li>以只写方式(O_WRONLY)打开 FIFO 时不会阻塞：
<ul>
<li>如果 FIFO 的读出端没有打开，直接返回失败；</li>
<li>如果 FIFO 的读出端已经打开，直接返回成功</li>
</ul>
</li>
<li>从以只读方式(O_RDONLY)打开的 FIFO 中读取数据不会阻塞：
<ul>
<li>FIFO 的写入端已打开，但 FIFO 中没有数据时，会产生错误：Resource temporarily unavailable</li>
<li>FIFO 的写入端已打开，且 FIFO 中有数据时，返回读出数据的长度(字节数)；</li>
<li>当 FIFO 写入端关闭时，返回 EOF(读出数据长度为 0)。</li>
</ul>
</li>
<li>向以只写方式(O_WRONLY)打开的 FIFO 写入数据时不会阻塞，立即返回：
<ul>
<li>当 FIFO 读出端关闭时，写入数据时出错，并产生 SIGPIPE 信号；</li>
<li>当 FIFO 读出端打开时，写入成功，写入的数据可以被读出端正常读出。</li>
</ul>
</li>
</ul>
</li>
<li>
<p>这种教条式的说明其实很枯燥，建议读者<strong>编写一些测试程序</strong>来体会上面的“教条”。</p>
</li>
</ul>
<h2 id="6-sigpipe-信号和-eof">6 SIGPIPE 信号和 EOF</h2>
<ul>
<li>
<p>在上一节的“教条”中，我们提出过两个要点：</p>
<ol>
<li>当一个向 FIFO 写入数据的进程将写入端关闭时，正在等待从 FIFO 中读取数据进程会收到一个 EOF；</li>
<li>当一个从 FIFO 读出数据的进程将读出端关闭时，向 FIFO 中写入数据的进程在写入数据时系统会发出一个 SIGPIPE 信号。</li>
</ol>
</li>
<li>
<p>这一节专门讨论与 FIFO 有关的 SIGPIPE 信号和 EOF(End Of File)；</p>
</li>
<li>
<p>在 Linux 的信号集有一个 SIGPIPE 信号是和 FIFO 相关的；</p>
</li>
<li>
<p>只有在向 FIFO 写入数据时才会产生 SIGPIPE 信号；也就是说，虽然读出端关闭，但如果不向 FIFO 中写入数据，也不会产生 SIGPIPE 信号；</p>
</li>
<li>
<p>写入数据时，<code>write()</code> 也会返回错误，所以，通常情况下并不一定要捕捉 SIGPIPE 信号；</p>
</li>
<li>
<p>源程序：<a href="https://gitee.com/whowin/whowin/blob/blog/sourcecodes/190011/fifo-sigpipe.c">fifo-sigpipe.c</a>(<strong>点击文件名下载源程序</strong>)演示了在向 FIFO 写入数据时，如何截获 SIGPIPE 信号；</p>
<ul>
<li>编译：<code>gcc -Wall fifo-sigpipe.c -o fifo-sigpipe</code></li>
<li>运行这个程序需要两个终端窗口，在第一个终端上运行：<code>./fifo-sigpipe</code>，程序运行后将被阻塞在 <code>open()</code> 上，在第二个终端上运行：<code>cat myfifo</code>，来模拟从 FIFO 中读取数据；</li>
<li>我们可以看到第一个终端中由 <code>fifo-sigpipe</code> 每 5 秒一次发出的信息可以在第二个终端上收到并显示出来，此时我们在第二个窗口中输入 <code>ctrl+c</code> 终止 <code>cat</code> 的运行，则在第一个窗口中可以看到截获到的 <code>SIGPIPE</code> 信号；</li>
<li><code>./fifo-sigpipe</code> 是 FIFO 的写入端，<code>cat fifo-sigpipe</code> 是 FIFO 的读出端，终止读出端，然后再次运行 <code>cat fifo-sigpipe</code>，可以继续收到 <code>fifo-sigpipe</code> 发出的信息。</li>
</ul>
</li>
<li>
<p>EOF 是读文件时常用的判断文件结束的方法，在 FIFO 上表示写入端被关闭：</p>
<ul>
<li>以阻塞方式打开 FIFO 进行读操作时，EOF 表示写入端已被关闭；</li>
<li>以阻塞方式打开 FIFO 进行读操作时，如果写入端打开但 FIFO 中没有数据，则会产生阻塞；</li>
<li>以非阻塞方式打开 FIFO 时，写入端关闭时，读出端会返回 EOF(读出数据长度为 0)；</li>
<li>以非阻塞方式打开 FIFO 时，写入端打开但 FIFO 中没有数据时，读出端不会返回 EOF，会产生错误：Resource temporarily unavailable</li>
</ul>
</li>
<li>
<p>源程序：<a href="https://gitee.com/whowin/whowin/blob/blog/sourcecodes/190011/fifo-eof.c">fifo-eof.c</a>(<strong>点击文件名下载源程序</strong>)演示了在从 FIFO 中读数据时，如何截获 EOF；</p>
<ul>
<li>编译：<code>gcc -Wall fifo-eof.c -o fifo-eof</code></li>
<li>运行这个程序需要两个终端窗口，在第一个终端上运行：<code>./fifo-eof</code>，程序运行后将被阻塞在 <code>open()</code> 上，在第二个终端上运行：<code>echo &quot;Hello world&quot;&gt;myfifo</code>，来模拟向 FIFO 写入数据；</li>
<li>当第二个终端的命令启动后，第一个终端上的 <code>fifo-eof</code> 程序会收到第二个终端的命令发来的数据，然后，第二个终端命令执行完毕退出，相当于关闭了 FIFO 的写入端，此时，可以在第一个终端的 <code>fifo-eof</code> 程序上看到捕捉到的 EOF；</li>
<li><code>./fifo-eof</code> 是 FIFO 的读出端，<code>echo &quot;Hello world&quot;&gt;myfifo</code> 是 FIFO 的写入端，终止写入端，然后再次运行 <code>echo &quot;Hello world&quot;&gt;myfifo</code>，<code>fifo-eof</code> 可以再次从 FIFO 中收到信息；</li>
<li>不管在打开 FIFO 时是阻塞状态还是非阻塞状态，当 FIFO 的写入端关闭时，读出端都会收到 EOF。</li>
</ul>
</li>
</ul>
<h2 id="7-使用流式文件操作-fifo-的一些差异">7 使用流式文件操作 FIFO 的一些差异</h2>
<ul>
<li>使用流式文件的操作函数(<code>fopen()/fread()/fwrite()/fclose()</code>等)是可以操作 FIFO 的，这个在前面的实例中已经有演示，但是与低级文件I/O的系统调用比是有一些差异的，本节将讨论已经发现的一些差异；</li>
<li>使用流式文件的方式从 FIFO 中读出数据时，如果遇到 EOF，必须要关闭 FIFO，然后再次打开，才能继续从 FIFO 中读取数据；
<ul>
<li><a href="https://gitee.com/whowin/whowin/blob/blog/sourcecodes/190011/fifo-server.c">fifo-server.c</a> 这个实例中，演示了流式文件方式从 FIFO 中读取数据时，遇到 EOF 需要再次打开 FIFO 的过程；</li>
<li>读者可以尝试修改这个程序，在遇到 EOF 后不关闭 FIFO，继续读取数据，是读不出数据的；</li>
<li>但是使用低级文件 I/O (<code>open()/read()/write()/close()</code>)操作 FIFO，在遇到 EOF 时，则不需要关闭 FIFO；</li>
<li><a href="https://gitee.com/whowin/whowin/blob/blog/sourcecodes/190011/fifo-eof.c">fifo-eof.c</a> 这个实例中，演示了使用低级文件 I/O 从 FIFO 中读取数据时，遇到 EOF 无需关闭 FIFO 的过程；</li>
</ul>
</li>
<li>当使用流式文件的方式向 FIFO 中写入数据时，因为流式文件缓存的原因，写入的数据可能不会马上进入到 FIFO 中；
<ul>
<li>如果希望写入的数据立即进入 FIFO 的话，应该在调用写入函数(<code>fputs()/fwrite()</code>等)之后，立即调用 <code>fflush()</code>，该函数的意义在于强制将缓冲区中的数据写入到指定的流式文件中；</li>
<li>使用低级文件 I/O 向 FIFO 中写入数据则没有这个问题；</li>
</ul>
</li>
<li>当使用流式文件的方式向 FIFO 中写入数据时，如果 FIFO 的读出端关闭，写入函数仍然会返回成功；
<ul>
<li>尽管函数调用返回成功，但向 FIFO 写入的数据会被忽略，再次打开的读出端无法读出这些数据；</li>
<li>和使用低级文件 I/O 写入 FIFO 时一样，会捕捉到一个 SIGPIPE 信号，所以使用流式文件的方式向 FIFO 写入数据时，要靠捕捉 SIGPIPE 信号来判断写入失败；</li>
<li>使用低级文件 I/O 写入 FIFO 时，如果 FIFO 读出端已关闭，写入函数(<code>write()</code>)会报告错误，这使得我们可以考虑不去捕捉 SIGPIPE 信号。</li>
</ul>
</li>
</ul>
<h2 id="8-后记">8 后记</h2>
<ul>
<li>
<p>本文涉及的所有观点均编有测试程序进行测试，限于篇幅，不能都列在文章中；</p>
</li>
<li>
<p>以本文提供的四个范例已经足够衍生出很多的测试程序：</p>
<ul>
<li><a href="https://gitee.com/whowin/whowin/blob/blog/sourcecodes/190011/fifo-server.c">fifo-server.c</a> - 是使用流式文件的方式从 FIFO 中读数据的，可以尝试将 <code>fopen()/fclose()</code> 放在循环外面，可以验证使用流式文件的方式读取 FIFO 时遇到 EOF 需要重新打开 FIFO 的观点；</li>
<li><a href="https://gitee.com/whowin/whowin/blob/blog/sourcecodes/190011/fifo-server.c">fifo-server.c</a> - 可以将这个程序改成使用低级文件 I/O 读取 FIFO 的方式，以比较流式文件的操作函数和低级文件 I/O 的操作函数之间的差异；</li>
<li><a href="https://gitee.com/whowin/whowin/blob/blog/sourcecodes/190011/fifo-client.c">fifo-client.c</a> - 可以加一个循环，使程序每隔 5 秒向 FIFO 写入一次数据，同时去掉 <code>fflush()</code>，可以验证流式文件的缓存对 FIFO 写入的影响；</li>
<li><a href="https://gitee.com/whowin/whowin/blob/blog/sourcecodes/190011/fifo-client.c">fifo-client.c</a> - 可以将其改成使用低级文件 I/O 写入 FIFO 的方式，以比较流式文件的操作函数和低级文件 I/O 的操作函数之间的差异；</li>
<li><a href="https://gitee.com/whowin/whowin/blob/blog/sourcecodes/190011/fifo-sigpipe.c">fifo-sigpipe.c</a> - 可以将其改为使用流式文件方式向 FIFO 写入数据，验证一下在读出端关闭时，<code>fputs()</code> 仍然返回成功的情况，同时体会一下如何在流式文件方式下捕捉 SIGPIPE 信号；</li>
</ul>
</li>
<li>
<p>本质上说，命名管道和匿名管道在内核中的实现基本是一样的，所以，命名管道其实也是半双工的，要建立一个全双工的命名管道只需建立两条管道即可；可以参考我的另一篇介绍匿名管道的文章<a href="https://whowin.gitee.io/post/blog/ipc/0010-ipc-example-of-anonymous-pipe/">《IPC之一：使用匿名管道进行父子进程间通信的例子》</a></p>
</li>
<li>
<p>命名管道如果不从文件系统中删除，会一直存在下去，这点和匿名管道有很大的区别，删除一个命名管道和删除一个普通文件无异；</p>
</li>
<li>
<p>为了让所有进程都可以访问到建立的命名管道，通常会把一个命名管道建在 <code>/tmp/</code> 下，好处有两点：</p>
<ol>
<li>这个目录的权限是 <code>0777</code>，所有的用户可进行读写；</li>
<li>这个目录是一个内存文件系统，并不在物理磁盘上，所以重新启动后你建立的命名管道也会消失，减少了维护。</li>
</ol>
</li>
<li>
<p>与匿名管道一样，Linux 下命名管道的缓冲区长度也是有限制的，最大长度为 4096 字节，定义在头文件：<code>linux/limits.h</code> 中：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="cp">#define PIPE_BUF        4096	</span><span class="cm">/* # bytes in atomic write to a pipe */</span><span class="cp">
</span></span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p>向 FIFO 中写入数据的长度不超过这个阈值，将是一个原子操作；</p>
</li>
<li>
<p>与匿名管道不同，由于命名管道在物理文件系统上建立了一个节点，所以其生命周期不会随着使用它的所有进程的终止而终止，只要命名管道没有被删除，可以一直使用下去。</p>
</li>
<li>
<p>与匿名管道一样，命名管道不仅可以传输字符串，也可以传输二进制数据的，也就是说，可以把一个结构完整第通过管道进行传输。</p>
</li>
<li>
<p>有关进程间通信(IPC)的的其它文章：</p>
<ul>
<li><a href="https://whowin.gitee.io/post/blog/ipc/0010-ipc-example-of-anonymous-pipe/">IPC之一：使用匿名管道进行父子进程间通信的例子</a></li>
<li><a href="https://whowin.gitee.io/post/blog/ipc/0011-ipc-examples-of-fifo/">IPC之二：使用命名管道(FIFO)进行进程间通信的例子</a></li>
<li><a href="https://whowin.gitee.io/post/blog/ipc/0013-systemv-message-queue/">IPC之三：使用 System V 消息队列进行进程间通信的实例</a></li>
<li><a href="https://whowin.gitee.io/post/blog/ipc/0014-posix-message-queue/">IPC之四：使用 POSIX 消息队列进行进程间通信的实例</a></li>
<li><a href="https://whowin.gitee.io/post/blog/ipc/0015-systemv-semaphore-sets/">IPC之五：使用 System V 信号量集解决经典的‘哲学家就餐问题‘</a></li>
</ul>
</li>
</ul>
<h2 id="欢迎订阅-进程间通信专栏httpsblogcsdnnetwhowincategory_12404164html"><strong>欢迎订阅 <a href="https://blog.csdn.net/whowin/category_12404164.html">『进程间通信专栏』</a></strong></h2>
<hr>
<p><strong>欢迎访问我的博客：https://whowin.cn</strong></p>
<p><strong>email: <a href="mailto:hengch@163.com">hengch@163.com</a></strong></p>
<p><img src="https://whowin.gitee.io/images/qrcode/sponsor-qrcode.png" alt="donation"></p>
<!-- for CSDN
[article01]: https://blog.csdn.net/whowin/article/details/132171311
[article02]: https://blog.csdn.net/whowin/article/details/132171930
[article03]: https://blog.csdn.net/whowin/article/details/132172172
[article04]: https://blog.csdn.net/whowin/article/details/134869490
[article05]: https://blog.csdn.net/whowin/article/details/134869636
-->
<!-- CSDN
[img01]: https://img-blog.csdnimg.cn/img_convert/8b0a919f4084f7941e8b4913b6d0f4db.png
[img02]: https://img-blog.csdnimg.cn/img_convert/16fb2f26b1d50451540fa8642ac56fbb.png
[img03]: https://img-blog.csdnimg.cn/img_convert/d76ec9eba314ac0095e83d3e2395ec59.png
-->
    </div>

    <div class="post-copyright">
  <p class="copyright-item">
    <span class="item-title">文章作者</span>
    <span class="item-content">whowin</span>
  </p>
  <p class="copyright-item">
    <span class="item-title">上次更新</span>
    <span class="item-content">
        2023-08-02
        
    </span>
  </p>
  
  
</div>
<footer class="post-footer">
      <div class="post-tags">
          <a href="/tags/linux/">Linux</a>
          <a href="/tags/%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1/">进程间通信</a>
          <a href="/tags/ipc/">IPC</a>
          <a href="/tags/fifo/">FIFO</a>
          <a href="/tags/%E5%91%BD%E5%90%8D%E7%AE%A1%E9%81%93/">命名管道</a>
          </div>
      <nav class="post-nav">
        <a class="prev" href="/post/blog/ipc/0013-systemv-message-queue/">
            <i class="iconfont icon-left"></i>
            <span class="prev-text nav-default">IPC之三：使用 System V 消息队列进行进程间通信的实例</span>
            <span class="prev-text nav-mobile">上一篇</span>
          </a>
        <a class="next" href="/post/blog/ipc/0010-ipc-example-of-anonymous-pipe/">
            <span class="next-text nav-default">IPC之一：使用匿名管道进行父子进程间通信的例子</span>
            <span class="next-text nav-mobile">下一篇</span>
            <i class="iconfont icon-right"></i>
          </a>
      </nav>
    </footer>
  </article>
        </div>
        

  <span id="/post/blog/ipc/0011-ipc-examples-of-fifo/" class="leancloud_visitors" data-flag-title="IPC之二：使用命名管道(FIFO)进行进程间通信的例子">
		<span class="post-meta-item-text">文章阅读量 </span>
		<span class="leancloud-visitors-count">0</span>
		<p></p>
	  </span>
  <div id="vcomments"></div>
  <script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
  <script src='//unpkg.com/valine/dist/Valine.min.js'></script>
  <script type="text/javascript">
    new Valine({
        el: '#vcomments' ,
        appId: 'OFCGzCfJRUglzOdzrqMGkbTR-gzGzoHsz',
        appKey: 'v7P29kPAEbsmaavaYPNhGhnF',
        notify:  false ,
        verify:  false ,
        avatar:'mm',
        placeholder: '说点什么吧...',
        visitor:  true 
    });
  </script>

  

      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="social-links">
      <a href="mailto:hengch@163.com" class="iconfont icon-email" title="email"></a>
  <a href="https://whowin.gitee.io/index.xml" type="application/rss+xml" class="iconfont icon-rss" title="rss"></a>
</div>
<div class="copyright">
  <span class="power-by">
    由 <a class="hexo-link" href="https://gohugo.io">Hugo</a> 强力驱动
  </span>
  <span class="division">|</span>
  <span class="theme-info">
    主题 - 
    <a class="theme-link" href="https://github.com/olOwOlo/hugo-theme-even">Even</a>
  </span>

  <div class="busuanzi-footer">
    <span id="busuanzi_container_site_pv"> 本站总访问量 <span id="busuanzi_value_site_pv"><img src="/img/spinner.svg" alt="spinner.svg"/></span> 次 </span>
      <span class="division">|</span>
    <span id="busuanzi_container_site_uv"> 本站总访客数 <span id="busuanzi_value_site_uv"><img src="/img/spinner.svg" alt="spinner.svg"/></span> 人 </span>
  </div>

  <span class="copyright-year">
    &copy; 
    2022 - 
    2024<span class="heart"><i class="iconfont icon-heart"></i></span><span>whowin</span>
  </span>
</div>

    </footer>

    <div class="back-to-top" id="back-to-top">
      <i class="iconfont icon-up"></i>
    </div>
  </div>
  
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/slideout@1.0.1/dist/slideout.min.js" integrity="sha256-t+zJ/g8/KXIJMjSVQdnibt4dlaDxc9zXr/9oNPeWqdg=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.1.20/dist/jquery.fancybox.min.js" integrity="sha256-XVLffZaxoWfGUEbdzuLi7pwaUJv1cecsQJQqGLe7axY=" crossorigin="anonymous"></script>



<script type="text/javascript" src="/js/main.min.64437849d125a2d603b3e71d6de5225d641a32d17168a58106e0b61852079683.js"></script>
  <script type="text/javascript">
    window.MathJax = {
      tex: {
        inlineMath: [['$','$'], ['\\(','\\)']],
        }
    };
  </script>
  <script async src="https://cdn.jsdelivr.net/npm/mathjax@3.0.5/es5/tex-mml-chtml.js" integrity="sha256-HGLuEfFcsUJGhvB8cQ8nr0gai9EucOOaIxFw7qxmd+w=" crossorigin="anonymous"></script>








</body>
</html>
